gl renderer: Render non-trivial transforms to a texture
authorTimm Bäder <mail@baedert.org>
Thu, 29 Nov 2018 07:09:02 +0000 (08:09 +0100)
committerTimm Bäder <mail@baedert.org>
Thu, 29 Nov 2018 07:50:18 +0000 (08:50 +0100)
This way we can e.g. render rotated clips, borders, etc.

gsk/gl/gskglrenderer.c
gsk/gl/gskglrenderops.c
gsk/gl/gskglrenderopsprivate.h

index a75f8b3823309441780beb25a94280c10ecc69e0..c92b71b0f2345d1f59d5774c8ea02e6bb1199b91 100644 (file)
@@ -219,6 +219,31 @@ gsk_rounded_rect_shrink_to_minimum (GskRoundedRect *self)
                                          MAX (self->corner[2].height, self->corner[3].height)) * 2);
 }
 
+static inline gboolean
+node_supports_transform (GskRenderNode *node)
+{
+  /* Some nodes can't handle non-trivial transforms without being
+   * rendered to a texture (e.g. rotated clips, etc.). Some however
+   * work just fine, mostly because they already draw their child
+   * to a texture and just render the texture manipulated in some
+   * way, think opacity or color matrix. */
+  const guint node_type = gsk_render_node_get_node_type (node);
+
+  switch (node_type)
+    {
+      case GSK_COLOR_NODE:
+      case GSK_OPACITY_NODE:
+      case GSK_COLOR_MATRIX_NODE:
+      case GSK_TEXTURE_NODE:
+        return TRUE;
+
+      default:
+        return FALSE;
+    }
+  return FALSE;
+}
+
+
 static void gsk_gl_renderer_setup_render_mode (GskGLRenderer   *self);
 static void add_offscreen_ops                 (GskGLRenderer   *self,
                                                RenderOpBuilder *builder,
@@ -736,7 +761,43 @@ render_transform_node (GskGLRenderer   *self,
   graphene_matrix_multiply (&transform, builder->current_modelview, &transformed_mv);
 
   ops_push_modelview (builder, &transformed_mv);
-  gsk_gl_renderer_add_render_ops (self, child, builder);
+  if (ops_modelview_is_simple (builder) ||
+      node_supports_transform (child))
+    {
+      gsk_gl_renderer_add_render_ops (self, child, builder);
+    }
+  else
+    {
+      const float min_x = builder->dx + child->bounds.origin.x;
+      const float min_y = builder->dy + child->bounds.origin.y;
+      const float max_x = min_x + child->bounds.size.width;
+      const float max_y = min_y + child->bounds.size.height;
+      const GskQuadVertex vertex_data[GL_N_VERTICES] = {
+        { { min_x, min_y }, { 0, 1 }, },
+        { { min_x, max_y }, { 0, 0 }, },
+        { { max_x, min_y }, { 1, 1 }, },
+
+        { { max_x, max_y }, { 1, 0 }, },
+        { { min_x, max_y }, { 0, 0 }, },
+        { { max_x, min_y }, { 1, 1 }, },
+      };
+      int texture_id;
+      gboolean is_offscreen;
+      /* For non-trivial transforms, we draw everything on a texture and then
+       * draw the texture transformed. */
+      /* TODO: We should compute a modelview containing only the "non-trivial"
+       *       part (e.g. the rotation) and use that. We want to keep the scale
+       *       for the texture.
+       */
+      add_offscreen_ops (self, builder,
+                         min_x, max_x, min_y, max_y,
+                         child,
+                         &texture_id, &is_offscreen,
+                         FALSE, TRUE);
+      ops_set_texture (builder, texture_id);
+      ops_set_program (builder, &self->blit_program);
+      ops_draw (builder, vertex_data);
+    }
   ops_pop_modelview (builder);
 }
 
index 1ac8f8866eb90e99c8a3edd57c66810971b025ff..85026d8e63c6e923f51379c7794e149caafdab5b 100644 (file)
@@ -116,6 +116,19 @@ ops_transform_bounds_modelview (const RenderOpBuilder *builder,
   graphene_rect_offset (dst, builder->dx, builder->dy);
 }
 
+gboolean
+ops_modelview_is_simple (const RenderOpBuilder *builder)
+{
+  const MatrixStackEntry *head;
+
+  g_assert (builder->mv_stack != NULL);
+  g_assert (builder->mv_stack->len >= 1);
+
+  head = &g_array_index (builder->mv_stack, MatrixStackEntry, builder->mv_stack->len - 1);
+
+  return head->metadata.simple;
+}
+
 void
 ops_set_program (RenderOpBuilder *builder,
                  const Program   *program)
index 7b0b1f824f86f8b0ff9b8be8df9a60f66768b419..97ce3a28b1f41c6c9b183f8bff4135b2eb4d1f76 100644 (file)
@@ -263,6 +263,7 @@ void              ops_finish             (RenderOpBuilder         *builder);
 void              ops_push_modelview     (RenderOpBuilder         *builder,
                                           const graphene_matrix_t *mv);
 void              ops_pop_modelview      (RenderOpBuilder         *builder);
+gboolean          ops_modelview_is_simple (const RenderOpBuilder  *builder);
 float             ops_get_scale          (const RenderOpBuilder   *builder);
 
 void              ops_set_program        (RenderOpBuilder         *builder,